package com.luxuewen.sxa.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.luxuewen.sxa.common.annotation.ApiAuth;
import com.luxuewen.sxa.common.enums.ResponseEnum;
import com.luxuewen.sxa.common.exception.ApiException;
import com.luxuewen.sxa.service.impl.SxaApisServiceImpl;
import com.luxuewen.sxa.utils.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author wen
 */
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private SxaApisServiceImpl sxaApisService;

    // 定义一个线程域，存放登录用户
    private static final ThreadLocal<Map<String, Object>> tl = new ThreadLocal<>();
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");

        //如果不映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }

        // 执行认证
        if (StrUtil.isBlank(token)) {
            throw new ApiException(ResponseEnum.INVALID_TOKEN.getCode(), "Token缺失，请重新获取!");
        } else {
            try {
                Map<String, Object> userInfos = JwtUtils.verifyToken(token);

                List<Integer> roleIds = new ArrayList<>();
                if (userInfos.get("roles") instanceof ArrayList<?>) {
                    boolean apiAuthFlag = false;

                    // 获取token角色
                    @SuppressWarnings("unchecked")
                    List<Map<String, Object>> roles = (List<Map<String, Object>>) userInfos.get("roles");
                    for (Map<String, Object> role : roles) {
                        if (Objects.equals(role.get("alias").toString(), "super_administrator")) {
                            apiAuthFlag = true;
                        }
                        roleIds.add((int)role.get("id"));
                    }


                    // 非超级管理员需要经过接口验证
                    if (!apiAuthFlag) {
                        // 未配置角色
                        if (roleIds.isEmpty()) {
                            throw new ApiException(ResponseEnum.FAILURE.getCode(), "未获取到系统访问角色，请重新登录再试!");
                        }

                        HandlerMethod handlerMethod = (HandlerMethod) handler;
                        Method method = handlerMethod.getMethod();
                        ApiAuth apiAuth = method.getAnnotation(ApiAuth.class);
                        if (apiAuth != null) {
                            String alias = apiAuth.alias();
                            sxaApisService.apiAuth(roleIds, alias);
                        }
                    }
                }

                userInfos.put("roleIds", roleIds);
                tl.set(userInfos);

                return true;
            } catch (SignatureVerificationException e) {
                throw new ApiException(ResponseEnum.INVALID_TOKEN.getCode(), "无效签名!");
            } catch (TokenExpiredException e) {
                throw new ApiException(ResponseEnum.INVALID_TOKEN.getCode(), "Token已过期，请重新获取!");
            } catch (AlgorithmMismatchException e) {
                throw new ApiException(ResponseEnum.INVALID_TOKEN.getCode(), "Token算法有误!");
            } catch (ApiException e) {
                throw new ApiException(e.getCode(), e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
                throw new ApiException(ResponseEnum.INVALID_TOKEN.getCode(), "Token无效，请重新获取!");
            }
        }
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //程序运行结束之后，删除线程
        tl.remove();
    }

    public static Map<String, Object> getLoginUser() {
        return tl.get();
    }
}
